package cn.com.open.itembank.util;

import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;

/**
 * Created by lucky on 2017/12/19.
 */
public class HttpRequestUtils {

    private static Logger logger = Logger.getLogger(HttpRequestUtils.class);

    /**
     * Do post string.
     *
     * @param baseUrl  the base url
     * @param apiUrl   the api url
     * @param paramMap the param map
     * @param headers  the headers
     * @return the string
     * @throws Exception the exception
     */
    public static String doPost(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers) throws Exception {
        return send(baseUrl, apiUrl, paramMap, headers, "POST");
    }

    /**
     * Do get string.
     *
     * @param baseUrl  the base url
     * @param apiUrl   the api url
     * @param paramMap the param map
     * @param headers  the headers
     * @return the string
     * @throws Exception the exception
     */
    public static String doGet(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers) throws Exception {
        return send(baseUrl, apiUrl, paramMap, headers, "GET");
    }

    /**
     * Do post string.
     *
     * @param baseUrl  the base url
     * @param apiUrl   the api url
     * @param paramMap the param map
     * @param headers  the headers
     * @return the string
     * @throws Exception the exception
     */
    public static String doDelete(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers) throws Exception {
        return send(baseUrl, apiUrl, paramMap, headers, "DELETE");
    }

    /**
     * 处理请求
     *
     * @param baseUrl       the base url
     * @param apiUrl        the api url
     * @param paramMap      the param map
     * @param headers       the headers
     * @param requestMethod the request method
     * @return string string
     * @throws Exception the exception
     */
    public static String send(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers,
                              String requestMethod) throws Exception {
        return send(baseUrl, apiUrl, paramMap, headers, requestMethod, null);
    }

    /**
     * 处理请求
     *
     * @param baseUrl       the base url
     * @param apiUrl        the api url
     * @param paramMap      the param map
     * @param headers       the headers
     * @param requestMethod the request method
     * @param files         the files
     * @return string string
     * @throws Exception the exception
     */
    public static String send(String baseUrl, String apiUrl, Map<String, Object> paramMap, Map<String, String> headers,
                              String requestMethod, Map<String, String> files) throws Exception {
        String resultStr = "";
        String filePath = null;
        DataInputStream in = null;
        try {

            System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
            String url = baseUrl + apiUrl;
            if (requestMethod.equals("GET")) {
                //GET请求直接在链接后面拼上请求参数
                if (paramMap != null) {
                    url += loadParamStr(paramMap);
                }
            }
            URL postURL = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) postURL.openConnection();
            conn.setDoInput(true);//允许输入
            //设置连接超时时间和读取超时时间，单位：毫秒
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(180000);
            conn.setRequestMethod(requestMethod);
            conn.setUseCaches(false);  // 不允许使用缓存
            conn.setInstanceFollowRedirects(true);
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("Accept", "application/json");//要求服务端返回的数据类型
            if (headers == null) {
                conn.setRequestProperty("Authorization", "Basic YTE5NjNhYzA4MTY1NWE2YToyMzFhNzFjMWZlYmI0MTFkOGFmZjAwNDgxOWZjMTgzZA==");
            } else if (!headers.containsKey("Authorization")) {
                conn.setRequestProperty("Authorization", "Basic YTE5NjNhYzA4MTY1NWE2YToyMzFhNzFjMWZlYmI0MTFkOGFmZjAwNDgxOWZjMTgzZA==");
            }

            if (requestMethod.equals("PUT") || requestMethod.equals("POST")) {
                // 发送POST请求必须设置为true  允许输出
                conn.setDoOutput(true);
            } else {
                //Get请求不需要DoOutPut
                conn.setDoOutput(false);
            }
//            conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");//json格式上传的模式
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");//表单上传的模式

            if (headers != null) {
                for (String pKey : headers.keySet()) {
                    if (!StringUtils.isEmpty(headers.get(pKey))) {
                        conn.setRequestProperty(pKey, headers.get(pKey));

                    }
                }
            }
            // POST的请求参数写在正文中
            int contentLength = 0;
            if (requestMethod.equals("PUT") || requestMethod.equals("POST")) {
                if (paramMap != null && !paramMap.isEmpty()) {
                    StringBuffer buffer = new StringBuffer();
                    for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                        buffer.append(entry.getKey()).append("=");
                        if (entry.getValue() != null) {
                            buffer.append(URLEncoder.encode(entry.getValue().toString(), "utf-8"));
                        } else {
                            buffer.append(" ");
                        }
                        buffer.append("&");
                    }
                    buffer.deleteCharAt(buffer.length() - 1);
//                    PrintWriter out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));
//                    out.print(buffer);
//                    out.flush();
//                    out.close();

                    String BOUNDARY = "";

                    if (files != null) {
                        BOUNDARY = UUID.randomUUID().toString();
                        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
                    }

                    DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
                    outStream.write(buffer.toString().getBytes());
                    contentLength = buffer.length();

                    // file
                    if (files != null) {
                        Iterator<Map.Entry<String, String>> iter = files.entrySet().iterator();
                        while (iter.hasNext()) {
                            Map.Entry<String, String> entry = iter.next();
                            String inputName = (String) entry.getKey();
                            String inputValue = (String) entry.getValue();
                            if (inputValue == null) {
                                continue;
                            }
                            filePath = inputValue;
                            File file = new File(inputValue);
                            String filename = file.getName();

                            StringBuffer strBuf = new StringBuffer();
                            strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                            strBuf.append("Content-Disposition: form-data; name=\"" + inputName + "\"; filename=\"" + filename + "\"\r\n");
                            strBuf.append("Content-Type:application/octet-stream;\r\n\r\n");

                            outStream.write(strBuf.toString().getBytes());

                            in = new DataInputStream(new FileInputStream(file));
                            int bytes = 0;
                            byte[] bufferOut = new byte[1024];
                            while ((bytes = in.read(bufferOut)) != -1) {
                                outStream.write(bufferOut, 0, bytes);
                            }
                            in.close();
                        }
                    }
                    if (!StringUtils.isEmpty(BOUNDARY)) {
                        byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
                        outStream.write(endData);
                    }
                    outStream.flush();
                    outStream.close();
                } else {
                    conn.setRequestProperty("Content-Length", "" + contentLength);
                }
            }

            if (requestMethod.equals("GET")) {
                //连接服务器
                conn.connect();
            }

            /// TODO: 2016/11/29 返回状态码需要后期完善，还需要对返回流，考虑字节流和图片流的区分，具体再问马工
            System.out.println(conn.getResponseCode());//响应码
            resultStr = readStrByCode(conn.getInputStream(), "utf-8");
            System.out.println(requestMethod + "请求[" + baseUrl + apiUrl + "]成功，请求结果：" + resultStr);
        } catch (IOException ex) {
            logger.error(ex.getMessage());
            System.out.println(requestMethod + "请求[" + baseUrl + apiUrl + "]Exception：" + ex.getMessage());
        } finally {
            if (in != null) {
                in.close();
            }
        }

        if (filePath != null && filePath != "") {
            try {
                File fileDel = new File(filePath);
                fileDel.delete();
            } catch (Exception ex) {
                logger.error(ex.getMessage());
            }
        }
        return resultStr;
    }

    /**
     * 以指定的格式来读取输入流
     */
    private static String readStrByCode(InputStream is, String code) throws Exception {
        StringBuilder builder = new StringBuilder();
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(is, code));
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line + "\n");
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException ex) {
                // TODO Auto-generated catch block
                logger.error(ex.getMessage());
            }
        }

        return builder.toString();
    }

    /**
     * 加载请求的path参数
     *
     * @param params
     * @return
     */
    private static StringBuffer loadParamStr(Map<String, Object> params) {
        StringBuffer paramtersb = new StringBuffer("");
        try {
            if (params != null) {
                Iterator it = params.keySet().iterator();
                paramtersb = new StringBuffer("?");
                while (it.hasNext()) {
                    String key = (String) it.next();
                    Object val = params.get(key);
                    if (val instanceof String[]) {
                        String[] s = (String[]) val;
                        paramtersb.append(key).append("=").append(URLEncoder.encode(s[0], "utf-8")).append("&");
                    } else {
                        paramtersb.append(key).append("=").append(URLEncoder.encode(val.toString(), "utf-8")).append("&");
                    }
                }
                paramtersb.deleteCharAt(paramtersb.length() - 1);
            }
        } catch (UnsupportedEncodingException ex) {
            logger.error(ex.getMessage());
        }
        return paramtersb;
    }
}
